package com.rainyun.rc.util;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**字符串简单解析工具类
 * 可以用静态方法,也可以用动态方法进行链式操作
 * 一般静态方法如果无法按规则识别字符串,返回null
 * */
public class RainStr {

	String str_todeal;

	/**创建工具对象,类似StringBuffer*/
	public RainStr(String todeal) {
		this.str_todeal = todeal;
	}
	
	/**获取处理好的字符串*/
	public String get() {return str_todeal;}
	/**获取处理好的字符串*/
	@Override
	public String toString() {return str_todeal;}
	
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#start(String todeal,String start)
	 * */
	public RainStr start(String start) {
		str_todeal = start(str_todeal,start);
		return this;
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#startEndFirst(String todeal,String start,String end)
	 * */
	public RainStr startEndFirst(String start,String end) {
		str_todeal = startEndFirst(str_todeal,start,end);
		return this;
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#end(String todeal,String end)
	 * */
	public RainStr end(String end) {
		str_todeal = end(str_todeal,end);
		return this;
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#inner(String todeal,String start,String end)
	 * */
	public RainStr inner(String start,String end) {
		str_todeal = inner(str_todeal,start,end);
		return this;
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#delColorCode(String todeal)
	 * */
	public RainStr delColorCode() {
		str_todeal = delColorCode(str_todeal);
		return this;
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#startEndSplit(String todeal,String start,String end)
	 * */
	public List<String> startEndSplit(String start,String end) {
		return startEndSplit(str_todeal,start,end);
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#split(String todeal,String split,int split_num)
	 * */
	public String[] split(String split,int split_num) {
		return split(str_todeal,split,split_num);
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#toEntry(String todeal,String split)
	 * */
	public StrEntry toEntry(String split) {
		return toEntry(str_todeal,split);
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#toInt(String todeal)
	 * */
	public Integer toInt(){
		return toInt(str_todeal);
	}
	/**功能对应该类的同名静态方法,但返回对象本身,用于链式操作
	 * @see RainStr#toDouble(String todeal)
	 * */
	public Double toDouble(){
		return toDouble(str_todeal);
	}
	
	//字符串方法
	
	/**判断字符串1是否以字符串2开头
	 * 是则返回截取开头后的字符串内容,否则返回null
	 * @param todeal 要处理的字符串
	 * @param start 判断开头
	 * @return 如输入参数("@aaa","@"),返回 "aaa"
	 * */
	public static String start(String todeal,String start) {
		if(todeal!=null&&todeal.startsWith(start))
			return todeal.substring(start.length());
		else
			return null;
	}
	/**判断字符串1是否以字符串2结尾
	 * 是则返回截取结尾后的字符串内容,否则返回null
	 * @param todeal 要处理的字符串
	 * @param end 判断结尾
	 * @return 如输入参数("aaa...","..."),返回 "aaa"
	 * */
	public static String end(String todeal,String end) {
		if(todeal!=null&&todeal.endsWith(end)) 
			return todeal.substring(0,todeal.length()-end.length());
		else
			return null;
	}
	/**判断字符串1是否以字符串2开头,以字符串3结尾
	 * 是则返回包围区间内的字符串内容,否则返回null
	 * @param todeal 要处理的字符串
	 * @param start 判断开头
	 * @param end 判断结尾
	 * @return 如输入参数("[aaa]","[","]"),返回 "aaa"
	 * */
	public static String inner(String todeal,String start,String end) {
		if(todeal!=null&&todeal.startsWith(start)&&todeal.endsWith(end))
		if(todeal.length()>=start.length()+end.length())
			return todeal.substring(start.length(),todeal.length()-end.length());
		
		return null;
	}
	/**寻找字符串1中的第一个包围结构,返回包围内容,找不到则返回null
	 * @param todeal 要寻找的字符串
	 * @param start 包围开头
	 * @param end 包围结尾
	 * @return 如输入参数("老八秘制[小汉堡]即实惠还[管饱]","[","]"),返回 "小汉堡"
	 * */
	public static String startEndFirst(String todeal,String start,String end) {
		if(todeal==null)return null;
		
		int b = todeal.indexOf(start);
		int e = todeal.indexOf(end,b);
		
		if(b!=-1&&e!=-1)
			return todeal.substring(b+start.length(),e);
		else
			return null;
	}
	/**通过字符串2分隔符分割字符串1(性能较高,非正则表达式)
	 * @param todeal 要处理的字符串
	 * @param split 分隔符
	 * @param split_num 最大分割段数,设置-1则不限制段数
	 * @return 如输入("192.168.0.1","."),返回数组{"192","168","0","1"}
	 * */
	public static String[] split(String todeal,String split,int split_num) {
		if(todeal==null)return null;
        int size = (todeal.length()-todeal.replace(split,"").length())/split.length()+1;
        //取分割后数组长度
        if(split_num!=-1)
        size = Math.min(size,split_num);
        //限定数组长度(段数)
        String[] arr = new String[size];
        int b = 0;
        int e = 0;
        for (int i = 0; i < size; i++) {
            e = todeal.indexOf(split, b);
            if (e == -1) {
                arr[i] = todeal.substring(b);
            } else {
                arr[i] = todeal.substring(b, e);
            }
            b = e+split.length();
        }
        return arr;
    }
	/**通过分隔符获取字符串键值映射,不符合分割要求则返回null
	 * 另外该方法会自动对字符串进行trim处理
	 * @param todeal 要处理的字符串
	 * @param split 分隔符
	 * @return 如输入("msg:哈哈哈哈",":"),返回字符串映射,可以通过getKey()和getValue()方法获取键值
	 * 如这里的键为"key",值为"哈哈哈哈"
	 * */
	public static StrEntry toEntry(String todeal,String split) {
		String[] en = split(todeal,split,2);
		if(en!=null&&en.length>=2) {
			String key = en[0].trim();
			String value = en[1].trim();
			return new StrEntry(key, value);
		}
		return null;
	}
	/**以开头结尾来分割字符串,返回分隔后的字符串集合<br>
	 * 如输入("我是一名{player}我喜欢{hobby}","{","}")<br>
	 * 返回集合{"我是一名","{player}","我喜欢","{hobby}"}<br>
	 * 另外面对套娃问题,如:我是一名{play{hobby}er}我喜欢,则识别为外层即{play{hobby}er} */
	public static List<String> startEndSplit(String todeal,String start,String end) {
		List<String> strlist = new ArrayList<String>();
		int b = 0;
		int e = 0;
		while(true) {
			int nb = todeal.indexOf(start,e);
			int ne = todeal.indexOf(end,nb);
			
			if(nb!=-1&&ne!=-1) {
				
				int ib = todeal.indexOf(start,nb+start.length());
				w1:while(true) {
					//解决套娃问题1
					int stack = 0;
					while(true) {
						if(ib!=-1&&ib<ne)
							stack++;
						else break;
						ib = todeal.indexOf(start,ib+start.length());
					}
					int olne = ne;
					for(int i=stack;i>0;i--) {
						int tne = todeal.indexOf(end,ne+end.length());
						if(tne==-1)break;
						ne = tne;
					}
					if(stack>0) {
						ib = todeal.indexOf(end,olne+end.length());
						if(ib==-1||ib>ne)
							break;
					}else break;
				}
//				while (true) {//解决套娃问题2
//					int oe = todeal.indexOf(end,ne+end.length());
//					int ob = todeal.indexOf(start,ne+end.length());
//					if(oe!=-1&&(ob==-1||oe<ob))
//						ne=oe;
//					else break;
//				}
				
				strlist.add(todeal.substring(e==0?0:e+end.length(),nb));
				strlist.add(todeal.substring(nb,ne+end.length()));
				b = nb;
				e = ne;
			}else {
				strlist.add(todeal.substring(e==0?0:e+end.length(),todeal.length()));
				break;
			}
		}
		return strlist;
	}
	/**在字符串每一个字符前插入一个§字符
	 * 最最通常的用法,输入("伤害值r"),返回"§伤§害§值§r"
	 * 这种操作可以让一些特定信息在客户端隐藏显示,并作为标识
	 * 通过delCode还原
	 * */
	public static String insertCode(String todeal){
		if(todeal==null)return null;
		String insert = "§";
		StringBuilder str1 = new StringBuilder(todeal);
		for(int i1 = todeal.length()-1;i1>=0;i1--){
			str1.insert(i1,insert);
		}
		return str1.toString();
	}
	/**删除字符串中所有§*/
	public static String delCode(String todeal){
		if(todeal==null)return null;
		return todeal.replace("§","");
	}
	/**字符串转Int,如果格式不符,返回null*/
	public static Integer toInt(String todeal){
		try {
			if(todeal==null)return null;
			return Integer.valueOf(todeal);
		}catch (NumberFormatException e) {
			return null;
		}
	}
	/**字符串转Double,如果格式不符,返回null*/
	public static Double toDouble(String todeal){
		try {
			if(todeal==null)return null;
			return Double.valueOf(todeal);
		}catch (NumberFormatException e) {
			return null;
		}
	}	
	/**删除字符串中所有颜色样式代码,支持§和&
	 * 如输入("&a腐&e乳"),返回"腐乳"*/
	public static String delColorCode(String todeal) {
		if(todeal==null)return null;
		return todeal.replaceAll("[§|&].","");
	}
	
	//集合方法
	
	/**通过字符串起始结束标签截取字符串集合,如果不符合截取条件,返回null
	 * @param todeal_list 要被截取的集合
	 * @param start_tag 开头标签,若集合中有字符串包含该标签,则认为对应集合下标为起始,若参数为null则忽视开头截取结尾之前的部分
	 * @param end_tag 结尾标签,若集合中有字符串包含该标签,则认为对应集合下标为结束,若参数为null则忽视结尾截取开头之后的部分
	 * @return 返回截取的集合,
	 * 如输入(集合{"==开始==","233","666","==结束=="},"开始","结束")
	 * 则返回{"233","666"}
	 * */
	public static List<String> subList(List<String> todeal_list,String start_tag,String end_tag) {
		int b = -1;
		int e = -1;
		int i=1;
		for(String str:todeal_list) {
			if(start_tag!=null&&str.contains(start_tag)) {
				b = i;
			}else if(end_tag!=null&&str.contains(end_tag)) {
				e = i;
			}
			i++;
		}
		List<String> sublist = null;
		if(b!=-1&&e!=-1&&e>b) {
			sublist = todeal_list.subList(b,e-1);
		}else if(b!=-1&&end_tag==null) {
			sublist = todeal_list.subList(b,todeal_list.size());
		}else if(e!=-1&&start_tag==null) {
			sublist = todeal_list.subList(0,e-1);
		}
		return sublist;		
	}
	
	/**传入字符串List集合,通过分隔符转换为Map集合,原理和toEntry方法类似
	 * 自动trim()处理
	 * 不符合分割要求的字符串会存入返回的Map中
	 * 用于处理如{"msg:喵喵喵","dam : 哈哈哈 "}的集合*/
	public static Map<String,String> toMap(List<String> todeal_list,String split) {
		LinkedHashMap<String, String> map = new LinkedHashMap<String,String>();
		for(String str:todeal_list) {
			StrEntry en = toEntry(str, split);
			if(en!=null)
			map.put(en.getKey(),en.getValue());
		}
		return map;
	}	
	/**反向分割,把数组根据分隔符转回字符串
	 * @param arr 数组
	 * @param split 分隔符
	 * @return 如输入数组({"123","456"},"|"),返回"123|456"
	 * */
	public static String join(String[] arr,String split) {
		StringBuffer str = new StringBuffer();
		if(arr!=null&&arr.length>0) {
			boolean firsted = false;
			for(String i:arr) {
				if(firsted)
					str.append(split);
				else firsted = true;
				str.append(i);
			}
		}
		return str.toString();
	}	
	
	/**计算字符串2在字符串1出现次数*/
	public static int count(String str,String find) {
		int t = str.length()-str.replace(find,"").length();
		if(t!=0)t/=find.length();
		return t;
	}
	
	/**获取字符串2在字符串1第num次出现的位置
	 * 找不到则返回-1*/
	public static int indexOf(String str,String find,int num) {
		int b=0;
		int idx=-1;
		while(--num>=0) {
			int in = str.indexOf(find,b);
			if(in!=-1){
				idx=in;
				b=in+find.length();
			}else break;
		}
		return idx;
	}
	
	/**字符串映射类*/
	public static class StrEntry{
		String key;
		String value;
		
		public StrEntry(String key,String value) {
			this.key = key;
			this.value = value;
		}
		
		public String getKey() {return key;}
		public String getValue() {return value;}
	}
	
}
